---
id: setup
title: Set up with Next.js
sidebar_label: Setup
slug: /client/nextjs/setup
---

import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';

## Recommended file structure

We recommend a file structure like this one, although it is not enforced by tRPC. This is what you'll see in [our examples](/main/example-apps.mdx). The rest of this page will take you through the process of adding tRPC in to this structure.

```graphql
.
├── prisma  # <-- if prisma is added
│   └── [..]
├── src
│   ├── pages
│   │   ├── _app.tsx  # <-- add `withTRPC()`-HOC here
│   │   ├── api
│   │   │   └── trpc
│   │   │       └── [trpc].ts  # <-- tRPC HTTP handler
│   │   └── [..]
│   ├── server
│   │   ├── routers
│   │   │   ├── _app.ts  # <-- main app router
│   │   │   ├── post.ts  # <-- sub routers
│   │   │   └── [..]
│   │   ├── context.ts   # <-- create app context
│   │   └── trpc.ts      # <-- procedure helpers
│   └── utils
│       └── trpc.ts  # <-- your typesafe tRPC hooks
└── [..]
```

## Add tRPC to existing Next.js project

### 1. Install deps

<Tabs>
  <TabItem value="npm" label="npm" default>

```sh
npm install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
```

  </TabItem>

<TabItem value="yarn" label="yarn">

```sh
yarn add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
```

</TabItem>

<TabItem value="pnpm" label="pnpm">

```sh
pnpm add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
```

</TabItem>

<TabItem value="bun" label="bun">

```sh
bun add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query@4 zod
```

</TabItem>
</Tabs>

The Next.js integration is actually a combination of our [React Query Integration](../react/introduction.mdx) and some Next.js specific integrations.

### 2. Enable strict mode

If you want to use Zod for input validation, make sure you have enabled strict mode in your `tsconfig.json`:

```diff title="tsconfig.json"
"compilerOptions": {
+   "strict": true
}
```

If strict mode is too harsh, you'll at least want to enable `strictNullChecks`:

```diff title="tsconfig.json"
"compilerOptions": {
+   "strictNullChecks": true
}
```

### 3. Create a tRPC router

Initialize your tRPC backend in `src/server/trpc.ts` using the `initTRPC` function, and create your first router. We're going to make a simple "hello world" router and procedure here - but for deeper information on creating your tRPC API you should refer to:

- the [Quickstart guide](/docs/quickstart) and [Backend usage docs](/docs/server/introduction) for tRPC information
- the [Next.js Adapter docs](/docs/server/adapters/nextjs) for mounting tRPC within your Next.js server.

<details>
<summary>View sample backend</summary>

```ts title='server/trpc.ts'
import { initTRPC } from '@trpc/server';

// Avoid exporting the entire t-object
// since it's not very descriptive.
// For instance, the use of a t variable
// is common in i18n libraries.
const t = initTRPC.create();

// Base router and procedure helpers
export const router = t.router;
export const procedure = t.procedure;
```

<br />

```ts title='server/routers/_app.ts'
import { z } from 'zod';
import { procedure, router } from '../trpc';

export const appRouter = router({
  hello: procedure
    .input(
      z.object({
        text: z.string(),
      }),
    )
    .query((opts) => {
      return {
        greeting: `hello ${opts.input.text}`,
      };
    }),
});

// export type definition of API
export type AppRouter = typeof appRouter;
```

<br />

```ts title='pages/api/trpc/[trpc].ts'
import * as trpcNext from '@trpc/server/adapters/next';
import { appRouter } from '../../../server/routers/_app';

// export API handler
// @see https://trpc.io/docs/server/adapters
export default trpcNext.createNextApiHandler({
  router: appRouter,
  createContext: () => ({}),
});
```

</details>

:::note
The backend above is using the [recommended file structure](#recommended-file-structure), but you can keep it simple and put everything in [an API handler directly](https://github.com/trpc/trpc/blob/main/examples/next-minimal-starter/src/pages/api/trpc/%5Btrpc%5D.ts) if you prefer.
:::

### 4. Create tRPC hooks

use the `createTRPCNext` function to create a set of strongly-typed hooks from your API's type signature.

```tsx title='utils/trpc.ts'
import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../server/routers/_app';

function getBaseUrl() {
  if (typeof window !== 'undefined')
    // browser should use relative path
    return '';

  if (process.env.VERCEL_URL)
    // reference for vercel.com
    return `https://${process.env.VERCEL_URL}`;

  if (process.env.RENDER_INTERNAL_HOSTNAME)
    // reference for render.com
    return `http://${process.env.RENDER_INTERNAL_HOSTNAME}:${process.env.PORT}`;

  // assume localhost
  return `http://localhost:${process.env.PORT ?? 3000}`;
}

export const trpc = createTRPCNext<AppRouter>({
  config(opts) {
    return {
      links: [
        httpBatchLink({
          /**
           * If you want to use SSR, you need to use the server's full URL
           * @link https://trpc.io/docs/ssr
           **/
          url: `${getBaseUrl()}/api/trpc`,

          // You can pass any HTTP headers you wish here
          async headers() {
            return {
              // authorization: getAuthCookie(),
            };
          },
        }),
      ],
    };
  },
  /**
   * @link https://trpc.io/docs/ssr
   **/
  ssr: false,
});
```

:::note
`createTRPCNext` does not work with the tRPC-v9 interop mode. If you are migrating from v9 using interop, you should continue using [the old way of initializing tRPC](../../../versioned_docs/version-9.x/nextjs/introduction.md#4-create-trpc-hooks).
:::

### 5. Configure `_app.tsx`

Wrap your root app page in the `trpc.withTRPC` HOC, similar to this:

```tsx title='pages/_app.tsx'
import type { AppType } from 'next/app';
import { trpc } from '../utils/trpc';

const MyApp: AppType = ({ Component, pageProps }) => {
  return <Component {...pageProps} />;
};

export default trpc.withTRPC(MyApp);
```

### 6. Make an API request

You're all set!

You can now use the React hooks you have just created to invoke your API. For more detail see the [React Query Integration](../react/introduction.mdx)

```tsx title='pages/index.tsx'
import { trpc } from '../utils/trpc';

export default function IndexPage() {
  const hello = trpc.hello.useQuery({ text: 'client' });
  if (!hello.data) {
    return <div>Loading...</div>;
  }
  return (
    <div>
      <p>{hello.data.greeting}</p>
    </div>
  );
}
```

## `createTRPCNext()` options

### `config`-callback

The `config`-argument is a function that returns an object that configures the tRPC and React Query clients. This function has a `ctx` input that gives you access to the Next.js `req` object, among other things. The returned value can contain the following properties:

- **Required**:
- `links` to customize the flow of data between tRPC Client and the tRPC Server. [Read more](/docs/client/links).
- Optional:
- `queryClientConfig`: a configuration object for the React Query `QueryClient` used internally by the tRPC React hooks: [QueryClient docs](https://tanstack.com/query/v4/docs/reference/QueryClient)
- `queryClient`: a React Query [QueryClient instance](https://tanstack.com/query/v4/docs/reference/QueryClient)
  - **Note:** You can only provide either a `queryClient` or a `queryClientConfig`.
- `transformer`: a transformer applied to outgoing payloads. Read more about [Data Transformers](/docs/server/data-transformers)
- `abortOnUnmount`: determines if in-flight requests will be cancelled on component unmount. This defaults to `false`.

### `overrides`: (default: `undefined`) {#overrides}

Configure [overrides for React Query's hooks](/docs/client/react/useUtils#invalidate-full-cache-on-every-mutation).

### `ssr`-boolean (default: `false`)

Whether tRPC should await queries when server-side rendering a page. Defaults to `false`.

### `responseMeta`-callback

Ability to set request headers and HTTP status when server-side rendering.

#### Example

```tsx title='utils/trpc.ts'
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../pages/api/trpc/[trpc]';

export const trpc = createTRPCNext<AppRouter>({
  config(opts) {
    /* [...] */
  },
  ssr: true,
  responseMeta(opts) {
    const { clientErrors } = opts;
    if (clientErrors.length) {
      // propagate first http error from API calls
      return {
        status: clientErrors[0].data?.httpStatus ?? 500,
      };
    }
    // cache full page for 1 day + revalidate once every second
    const ONE_DAY_IN_SECONDS = 60 * 60 * 24;
    return {
      'Cache-Control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
    };
  },
});
```

## Next steps

Browse the rest of the docs to learn more about things like [authorization](/docs/server/authorization), [middlewares](/docs/server/middlewares), and [error handling](/docs/server/error-handling).

You can also find information about [queries](/docs/client/react/usequery) and [mutations](/docs/client/react/useMutation) now that you're using `@trpc/react-query`.
